#include "internal.h"

int sched_rr_timeslice = RR_TIMESLICE;

/***********************************************************/
#define for_each_sched_rt_entity(rt_se) \
    for (; rt_se; rt_se = NULL)


static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se)
{
    return container_of(rt_se, struct task_struct, rt);
}

static inline struct rq *rq_of_rt_se(struct sched_rt_entity *rt_se)
{
    struct task_struct *p = rt_task_of(rt_se);

    return task_rq(p);
}

static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se)
{
    struct rq *rq = rq_of_rt_se(rt_se);

    return &rq->rt;
}

static inline int rt_se_prio(struct sched_rt_entity *rt_se)
{
    return rt_task_of(rt_se)->prio;
}

static inline unsigned int rt_se_nr_running(struct sched_rt_entity *rt_se)
{
    return 1;
}

static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
{
    return container_of(rt_rq, struct rq, rt);
}

static inline unsigned int rt_se_rr_nr_running(struct sched_rt_entity *rt_se)
{
    struct task_struct *tsk;

    tsk = rt_task_of(rt_se);

    return (tsk->policy == SCHED_RR) ? 1 : 0;
}

static inline void inc_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
{
    struct rq *rq = rq_of_rt_rq(rt_rq);

    rt_rq->rt_nr_running += rt_se_nr_running(rt_se);
    rt_rq->rr_nr_running += rt_se_rr_nr_running(rt_se);
}

static inline void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
{
    struct rq *rq = rq_of_rt_rq(rt_rq);

    rt_rq->rt_nr_running -= rt_se_nr_running(rt_se);
    rt_rq->rr_nr_running -= rt_se_rr_nr_running(rt_se);
}

static inline bool sched_rt_runnable(struct rq *rq)
{
    return rq->rt.rt_queued > 0;
}

static inline int on_rt_rq(struct sched_rt_entity *rt_se)
{
    return rt_se->on_rq;
}

/*
 * Update the current task's runtime statistics. Skip current tasks that
 * are not in our scheduling class.
 */
static void update_curr_rt(struct rq *rq)
{
    struct task_struct *donor = rq->donor;
    s64 delta_exec;

    if (donor->sched_class != &rt_sched_class)
        return;

    delta_exec = update_curr_common(rq);
    if (unlikely(delta_exec <= 0))
        return;

#ifdef CONFIG_RT_GROUP_SCHED
    struct sched_rt_entity *rt_se = &donor->rt;

    if (!rt_bandwidth_enabled())
        return;

    for_each_sched_rt_entity(rt_se)
    {
        struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
        int exceeded;

        if (sched_rt_runtime(rt_rq) != RUNTIME_INF)
        {
            raw_spin_lock(&rt_rq->rt_runtime_lock);
            rt_rq->rt_time += delta_exec;
            exceeded = sched_rt_runtime_exceeded(rt_rq);
            if (exceeded)
                resched_curr(rq);
            raw_spin_unlock(&rt_rq->rt_runtime_lock);
            if (exceeded)
                do_start_rt_bandwidth(sched_rt_bandwidth(rt_rq));
        }
    }
#endif
}

static inline void watchdog(struct rq *rq, struct task_struct *p) { }

#include "rt-requeue.c"
#include "rt-smp.c"
#include "rt-group_sched.c"
#include "rt-schedstat.c"
#include "rt-dequeue_task.c"
#include "rt-enqueue_task.c"
#include "rt-pick_task.c"
#include "rt-task_tick.c"
#include "rt-prio_changed.c"
#include "rt-switched_to.c"
#include "rt-wakeup_preempt.c"

static void yield_task_rt(struct rq *rq)
{
	requeue_task_rt(rq, rq->curr, 0);
}

static void init_rt_rq(struct rq *rq)
{
    struct rt_rq *rt_rq = &rq->rt;

    struct rt_prio_array *array;
    int i;

    array = &rt_rq->active;
    for (i = 0; i < MAX_RT_PRIO; i++)
    {
        INIT_LIST_HEAD(array->queue + i);
        __clear_bit(i, array->bitmap);
    }

    /* delimiter for bitsearch: */
    __set_bit(MAX_RT_PRIO, array->bitmap);

    rt_rq->rt_queued = 0;
}

DEFINE_SCHED_CLASS(rt) = {
    .enqueue_task = enqueue_task_rt,
    .dequeue_task = dequeue_task_rt,
    .yield_task = yield_task_rt,

    .pick_task = pick_task_rt,
    .put_prev_task = put_prev_task_rt,
    .set_next_task = set_next_task_rt,

    .task_tick = task_tick_rt,

    .wakeup_preempt = wakeup_preempt_rt,

    .prio_changed = prio_changed_rt,
    .switched_to = switched_to_rt,

    .update_curr = update_curr_rt,

    .init_rq = init_rt_rq,
};

void init_rt_entity(struct task_struct *p)
{
    INIT_LIST_HEAD(&p->rt.run_list);
    p->rt.time_slice = sched_rr_timeslice;
    p->rt.on_rq = 0;
    p->rt.on_list = 0;
}
